/*************************************************************************
 *                                                                       *
 * This file is part of the DogosFrame distribution.  For full copyright *
 * information, see COPYRIGHT and COPYING.LESSER.                        *
 *                                                                       *
 * Author:           sqbang                                              *
 * Email:            sqbang@ustc.edu                                     *
 *                                                                       *
 *************************************************************************/

#ifndef DOGOS_include_COMMON_tbox_IEEE_h
#define DOGOS_include_COMMON_tbox_IEEE_h

//C++ headers
#include <vector>

//COMMON headers
#include "COMMON/base/Common.h"
#include "COMMON/tbox/MathUtilities.h"

namespace DOGOS
{

/**
 * Class IEEE is a utility providing rotuines for managing IEEE trap
 * handlers and data set to signaling NaNs.  Signaling NaNs force
 * a trap if they are used in a numerical operation, so they are a
 * useful way to track uninitialized floating point data.  Signaling
 * NaN's may only be used for double and float data (and the real
 * ans imaginary parts of Complex data) and so operations are
 * provided here for those types only.
 *
 * IMPORTANT: To properly trap operations based on signaling NaN values,
 *            the routine IEEE::setup_floating_point_exception_handlers()
 *            must be called.  This is normally done in the
 *            DogosManager::startup() routine.
 *
 * Note that all operations provided by this class (except for setting
 * up exception handling) are implemented in @see tbox::MathUtilities.
 * Operations are provided by this class since it is not templated on
 * data type and so calling the operations provided here may be easier
 * in some cases, such as in codes built based on earlier versions
 * of DOGOS.  See the tbox::MathUtilities header file for details
 * about the routines.
 *
 * @see MathUtilities
 */
class IEEE
{
public:

    /**
     * Get the IEEE float signaling NaN on architectures that support it.
     * Using this value in a numerical expression will cause a program abort.
     */
    static inline float
    get_signaling_float_NaN();

    /**
     * Get the IEEE double signaling NaN on architectures that support it.
     * Using this value in a numerical expression will cause a program abort.
     */
    static inline double
    get_signaling_NaN();

    /**
     * Get the Complex value with real and imaginary parts set to the
     * IEEE double signaling NaN on architectures that support it.
     * Using this value in a numerical expression will cause a program abort.
     */
    static inline Complex
    get_signaling_complex_NaN();

    /**
     * Set supplied float value to the signaling NaN.
     */
    static inline void
    set_NaN(
        float& f);

    /**
     * Set supplied double value to the signaling NaN.
     */
    static inline void
    set_NaN(
        double& d);

    /**
     * Set real and imaginary parts of supplied Complex value to the
     * double signaling NaN.
     */
    static inline void
    set_NaN(
        Complex& dc);

    /**
     * Initialize a vector of floats to signaling NaNs.  Before using this
     * array in any operation, the NaN value should be reset.  Otherwise,
     * an unrecoverable exception will result (as long as floating point
     * exception handling is supported by the compiler).
     */
    static inline void
    initialize_vector_to_signaling_NaN(
        std::vector<float>& vector);

    /**
     * Initialize a vector of doubles to signaling NaNs.  Before using this
     * array in any operation, the NaN value should be reset.  Otherwise,
     * an unrecoverable exception will result (as long as floating point
     * exception handling is supported by the compiler).
     */
    static inline void
    initialize_vector_to_signaling_NaN(
        std::vector<double>& vector);

    /**
     * Initialize a vector of Complex to signaling NaNs.  Before using this
     * array in any operation, the NaN value should be reset.  Otherwise,
     * an unrecoverable exception will result (as long as floating point
     * exception handling is supported by the compiler).
     */
    static inline void
    initialize_vector_to_signaling_NaN(
        std::vector<Complex>& vector);

    /**
     * Initialize an array of floats to signaling NaNs.  Before using this
     * array in any operation, the NaN value should be reset.  Otherwise,
     * an unrecoverable exception will result (as long as floating point
     * exception handling is supported by the compiler).
     */
    static inline void
    initialize_array_to_signaling_NaN(
        float* array,
        int n = 1);

    /**
     * Initialize an array of doubles to signaling NaNs.  Before using this
     * array in any operation, the NaN value should be reset.  Otherwise,
     * an unrecoverable exception will result (as long as floating point
     * exception handling is supported by the compiler).
     */
    static inline void
    initialize_array_to_signaling_NaN(
        double* array,
        int n = 1);

    /**
     * Initialize an array of Complex to signaling NaNs.  Before using this
     * array in any operation, the NaN value should be reset.  Otherwise,
     * an unrecoverable exception will result (as long as floating point
     * exception handling is supported by the compiler).
     */
    static inline void
    initialize_array_to_signaling_NaN(
        Complex* array,
        int n = 1);

    /**
     * Return true if the supplied float value is NaN; else, false.
     */
    static inline bool
    is_NaN(
        const float& f);

    /**
     * Return true if the supplied double value is NaN; else, false.
     */
    static inline bool
    is_NaN(
        const double& d);

    /**
     * Return true if if either real and imaginary part of the supplied
     * Complex value is NaN; else, false.
     */
    static inline bool
    is_NaN(
        const Complex& dc);

public:

    /**
     * Set up IEEE exception handlers so that normal IEEE exceptions will
     * cause a program abort.  This is useful for tracking down errors.
     * Note, however, that this may cause problems if your code relies on
     * IEEE underflow or overflow traps.
     */
    static void
    setup_floating_point_exception_handlers();
};

}

#include "COMMON/tbox/IEEE.inl"

#endif
